//------------------------------------------------------------------------------
// Copyright (c) 2008 www.dnaide.com
// Licensed under the MIT (MIT-LICENSE.txt)
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Globalization;
using System.Text.RegularExpressions;

using DNAide.Core;

namespace DNAide.Web
{
	/// <summary>
	/// Url based helper methods
	/// </summary>
	public static partial class UrlAide
	{

		#region Methods

		public static String GetSchemeHostAndPort()
		{
			return GetSchemeHostAndPort(HttpContext.Current);
		}


		/// <summary></summary>
		public static String GetSchemeHostAndPort(HttpContext context)
		{
			if (context == null)
			{
				return String.Empty;
			}
			string retval = String.Concat(context.Request.Url.Scheme, "://", context.Request.Url.Host);
			if (!context.Request.Url.IsDefaultPort)
			{
				retval = String.Concat(retval, ":", context.Request.Url.Port);
			}
			return retval;
		}


		public static String GetSchemeHostAndPortForwardSlashAppended()
		{
			return GetSchemeHostAndPortForwardSlashAppended(HttpContext.Current);
		}

		/// <summary></summary>
		public static String GetSchemeHostAndPortForwardSlashAppended(HttpContext context)
		{
			return String.Concat(GetSchemeHostAndPort(context), "/");
		}

		/// <summary>
		/// Returns the current application path. Will always ensure that "/" is appended to the end
		/// </summary>
		public static String GetApplicationPathForwardSlashAppended()
		{
			string retval = (HttpRuntime.AppDomainAppVirtualPath.Length > 1) ? HttpRuntime.AppDomainAppVirtualPath : String.Empty;
			return String.Concat(retval, "/");
		}

		/// <summary>
		/// Given a url, replace ~/ with the current app's pathToCheck
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static String Resolve(String value)
		{
			if (value == null)
			{
				return string.Empty;
			}
			string applicationPath = (HttpRuntime.AppDomainAppVirtualPath.Length > 1) ? HttpRuntime.AppDomainAppVirtualPath : String.Empty;
			return Resolve(value, applicationPath);
		}

		/// <summary>
		/// Given a url, replace ~/ with the app pathToCheck
		/// </summary>
		/// <param name="value"></param>
		/// <param name="applicationPath"></param>
		/// <returns></returns>
		public static String Resolve(String value, String applicationPath)
		{
			if (!string.IsNullOrEmpty(value))
			{
				if (value.StartsWith("^~/"))
					return "^" + applicationPath + value.Substring(2);
				else if (value.StartsWith("~/"))
					return applicationPath + value.Substring(1);
			}
			return value;
		}


		/// <summary>
		/// Returns whether the virtual pathToCheck is relative.  Note that this returns true for
		/// app relative paths (e.g. "~/sub/foo.aspx")
		/// </summary>
		public static Boolean IsRelativeUrl(String virtualPath)
		{
			if (string.IsNullOrEmpty(virtualPath))
			{
				return false;
			}

			// If it has a protocol, it's not relative
			if (virtualPath.IndexOf(":", StringComparison.Ordinal) != -1)
				return false;

			return !IsRooted(virtualPath);
		}

		/// <summary>
		/// </summary>
		/// <param name="basePath"></param>
		/// <returns></returns>
		public static Boolean IsRooted(String basePath)
		{
			return (String.IsNullOrEmpty(basePath) || basePath[0] == '/' || basePath[0] == '\\');
		}


		/// <summary></summary>
		public static String MakeUrlSafe(String value)
		{
			return MakeUrlSafe(value, true, "-", CultureInfo.CurrentCulture);
		}

		/// <summary></summary>
		public static String MakeUrlSafe(String value, Boolean toLowercase, String wordSeparator, CultureInfo culture)
		{
			value = Regex.Replace(value, "[^a-zA-Z0-9 ]", " ");
			/* Replace multiple spaces */
			value = Regex.Replace(value, @"\s{2,}", " ");
			value = value.Replace(" ", wordSeparator);
			if (toLowercase)
			{
				value = value.ToLower(culture);
			}
			return value;
		}

		/// <summary></summary>
		public static String MakeUrlSafeInvariant(String value)
		{
			return MakeUrlSafe(value, true, "-", CultureInfo.InvariantCulture);
		}


		/// <summary>
		/// Ensures a url string is prefixed with http://
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static String PrefixScheme(String value)
		{
			return PrefixScheme(value, SchemeType.http);
		}


		/// <summary>
		/// Ensures a url string is prefixed with a scheme
		/// </summary>
		/// <param name="value"></param>
		/// <param name="scheme"></param>
		/// <returns></returns>
		public static String PrefixScheme(String value, SchemeType scheme)
		{
			if (String.IsNullOrEmpty(value))
			{
				return string.Empty;
			}

			if (value.ToLowerInvariant().StartsWith("http://") ||
				value.ToLowerInvariant().StartsWith("https://") ||
				value.ToLowerInvariant().StartsWith("ftp://") ||
				value.ToLowerInvariant().StartsWith("file://") ||
				value.ToLowerInvariant().StartsWith("gopher://"))
			{
				return value;
			}
			return String.Concat(scheme.ToString(), "://", value);
		}

		/// <summary>
		/// </summary>
		/// <param name="url"></param>
		/// <param name="queryStringParam"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public static String ChangeQueryStringValueInUrl(String url, String queryStringParam, String value)
		{
			string retval = url;
			url = CastAide.AsStringInvariant(url);
			queryStringParam = CastAide.AsStringInvariant(queryStringParam);
			value = HttpContext.Current.Server.UrlEncode(CastAide.AsStringInvariant(value));
			if (url.IndexOf("?") == -1)
			{
				// Add the parameter
				retval = StringAide.FormatInvariant("{0}?{1}={2}", url, queryStringParam, value);
			}
			else
			{
				if (url.IndexOf(queryStringParam) == -1)
				{
					// Add the parameter
					retval = StringAide.FormatInvariant("{0}&{1}={2}", url, queryStringParam, value);
				}
				else
				{
					// Replace the parameter
					string[] temp = url.Split(new char[] { '?' });
					string[] temp2 = temp[1].Split(new char[] { '&' });
					string newQS = string.Empty;
					foreach (string qsParam in temp2)
					{
						if (newQS.Length > 0)
							newQS += "&";
						if (qsParam.IndexOf(queryStringParam + "=") > -1)
							newQS += queryStringParam + "=" + value;
						else
							newQS += qsParam;
					}
					retval = String.Concat(temp[0], "?" + newQS);
				}
			}
			return retval;
		}

		#endregion

		/// <summary>
		/// </summary>
		public enum SchemeType
		{
			/// <summary></summary>
			http,
			/// <summary></summary>
			https,
			/// <summary></summary>
			ftp,
			/// <summary></summary>
			file
		}

	}
}
